﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace MetroWPF.Controls
{
    public class ProgressBar : System.Windows.Controls.ProgressBar
    {
        public static readonly DependencyProperty ContainerAnimationEndPositionTemplateSettingProperty =
            DependencyProperty.Register("ContainerAnimationEndPositionTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public static readonly DependencyProperty ContainerAnimationStartPositionTemplateSettingProperty =
            DependencyProperty.Register("ContainerAnimationStartPositionTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public static readonly DependencyProperty EllipseAnimationEndPositionTemplateSettingProperty =
            DependencyProperty.Register("EllipseAnimationEndPositionTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public static readonly DependencyProperty EllipseAnimationWellPositionTemplateSettingProperty =
            DependencyProperty.Register("EllipseAnimationWellPositionTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public static readonly DependencyProperty EllipseDiameterTemplateSettingProperty =
            DependencyProperty.Register("EllipseDiameterTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public static readonly DependencyProperty EllipseOffsetTemplateSettingProperty =
            DependencyProperty.Register("EllipseOffsetTemplateSetting", typeof(double), typeof(ProgressBar), new PropertyMetadata(default(double)));

        public ProgressBar()
            : base()
        {
            this.SizeChanged += OnSizeChanged;
        }

        /// <summary>
        /// Gets the target To point of the container animation that animates the ProgressBar.
        /// </summary>
        public double ContainerAnimationEndPositionTemplateSetting
        {
            get { return (double)GetValue(ContainerAnimationEndPositionTemplateSettingProperty); }
            private set { SetValue(ContainerAnimationEndPositionTemplateSettingProperty, value); }
        }

        /// <summary>
        /// Gets the From point of the container animation that animates the ProgressBar.
        /// </summary>
        public double ContainerAnimationStartPositionTemplateSetting
        {
            get { return (double)GetValue(ContainerAnimationStartPositionTemplateSettingProperty); }
            private set { SetValue(ContainerAnimationStartPositionTemplateSettingProperty, value); }
        }

        /// <summary>
        /// Gets the To point of the Ellipse animation that animates the ProgressBar.
        /// </summary>
        public double EllipseAnimationEndPositionTemplateSetting
        {
            get { return (double)GetValue(EllipseAnimationEndPositionTemplateSettingProperty); }
            private set { SetValue(EllipseAnimationEndPositionTemplateSettingProperty, value); }
        }

        /// <summary>
        /// Gets the stopped point of the Ellipse animation that animates the ProgressBar.
        /// </summary>
        public double EllipseAnimationWellPositionTemplateSetting
        {
            get { return (double)GetValue(EllipseAnimationWellPositionTemplateSettingProperty); }
            private set { SetValue(EllipseAnimationWellPositionTemplateSettingProperty, value); }
        }

        /// <summary>
        /// Gets the template-defined diameter of the Ellipse element that is animated in a templated ProgressBar.
        /// </summary>
        public double EllipseDiameterTemplateSetting
        {
            get { return (double)GetValue(EllipseDiameterTemplateSettingProperty); }
            private set { SetValue(EllipseDiameterTemplateSettingProperty, value); }
        }

        /// <summary>
        /// Gets the template-defined offset position of the Ellipse element that is animated in a templated ProgressBar.
        /// </summary>
        public double EllipseOffsetTemplateSetting
        {
            get { return (double)GetValue(EllipseOffsetTemplateSettingProperty); }
            private set { SetValue(EllipseOffsetTemplateSettingProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.UpdateTemplateSettings();
        }

        private Storyboard CreateStoryBoard()
        {
            var storyBoard = new Storyboard() { RepeatBehavior = RepeatBehavior.Forever };

            var containerAnimation = new DoubleAnimation() { Duration = TimeSpan.Parse("0:0:3.917"), From = this.ContainerAnimationStartPositionTemplateSetting, To = this.ContainerAnimationEndPositionTemplateSetting };
            Storyboard.SetTarget(containerAnimation, this.Template.FindName("EllipseGrid", this) as DependencyObject);
            Storyboard.SetTargetProperty(containerAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
            storyBoard.Children.Add(containerAnimation);

            System.Diagnostics.Debugger.Break();

            for (int i = 1; i <= 5; i++)
            {
                var eAnimation = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(eAnimation, this.Template.FindName("E" + i.ToString(), this) as DependencyObject);

                Storyboard.SetTargetProperty(eAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
                eAnimation.KeyFrames.Add(
                    new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0)));
                eAnimation.KeyFrames.Add(
                    new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0.5 / 3 * i)));
                eAnimation.KeyFrames.Add(
                    new SplineDoubleKeyFrame(this.EllipseAnimationWellPositionTemplateSetting, TimeSpan.FromSeconds(0.5 / 3 * i + 1), new KeySpline(0.4, 0, 0.6, 1)));
                eAnimation.KeyFrames.Add(
                    new EasingDoubleKeyFrame(this.EllipseAnimationWellPositionTemplateSetting, TimeSpan.FromSeconds(0.5 / 3 * i + 2)));
                eAnimation.KeyFrames.Add(
                  new SplineDoubleKeyFrame(this.EllipseAnimationEndPositionTemplateSetting, TimeSpan.FromSeconds(0.5 / 3 * i + 3), new KeySpline(0.4, 0, 0.6, 1)));
                storyBoard.Children.Add(eAnimation);
            }

            for (int i = 1; i <= 5; i++)
            {
                var bAnimtion = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(bAnimtion, this.Template.FindName("B" + i.ToString(), this) as DependencyObject);
                Storyboard.SetTargetProperty(bAnimtion, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
                bAnimtion.KeyFrames.Add(
                    new EasingDoubleKeyFrame(-50, TimeSpan.FromSeconds(0)));
                bAnimtion.KeyFrames.Add(
                    new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0.5 / 3 * (i - 1) + 0.5)));
                bAnimtion.KeyFrames.Add(
                    new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0.5 / 3 * (i - 1) + 2)));
                bAnimtion.KeyFrames.Add(
                    new EasingDoubleKeyFrame(100, TimeSpan.FromSeconds(0.5 / 3 * (i - 1) + 3)));
                storyBoard.Children.Add(bAnimtion);
            }

            for (int i = 1; i <= 5; i++)
            {
                var eColAnimation = new ObjectAnimationUsingKeyFrames();
                Storyboard.SetTarget(eColAnimation, this.Template.FindName("E" + i.ToString(), this) as DependencyObject);
                Storyboard.SetTargetProperty(eColAnimation, new PropertyPath(Ellipse.FillProperty));
                eColAnimation.KeyFrames.Add(
                    new DiscreteObjectKeyFrame(/*Application.Current.Resources.FindName("ProgressBarIndeterminateForegroundThemeBrush")*/new SolidColorBrush(Colors.Blue), TimeSpan.FromSeconds(0)));
                storyBoard.Children.Add(eColAnimation);
            }

            for (int i = 1; i <= 5; i++)
            {
                var eOpaAnimation = new DoubleAnimationUsingKeyFrames();
                Storyboard.SetTarget(eOpaAnimation, this.Template.FindName("E" + i.ToString(), this) as DependencyObject);
                Storyboard.SetTargetProperty(eOpaAnimation, new PropertyPath(Ellipse.OpacityProperty));
                if (i > 1)
                {
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0)));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0.5 / 3 * (i - 1))));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(1, TimeSpan.FromSeconds(0.5 / 3 * (i - 1))));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(1, TimeSpan.FromSeconds(0.5 / 3 * (i - 1) + 3)));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(0.5 / 3 * (i - 1) + 3)));
                    storyBoard.Children.Add(eOpaAnimation);
                }
                else
                {
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(1, TimeSpan.FromSeconds(0)));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(1, TimeSpan.FromSeconds(3)));
                    eOpaAnimation.KeyFrames.Add(
                        new EasingDoubleKeyFrame(0, TimeSpan.FromSeconds(3)));
                    storyBoard.Children.Add(eOpaAnimation);
                }
            }

            var indicatorAnimation = new DoubleAnimation() { To = 0, Duration = TimeSpan.FromSeconds(0) };
            Storyboard.SetTarget(indicatorAnimation, this.FindName("PART_Indicator") as DependencyObject);
            Storyboard.SetTargetProperty(indicatorAnimation, new PropertyPath(System.Windows.Controls.Grid.OpacityProperty));
            //storyBoard.Children.Add(indicatorAnimation);

            var backgroundAnimation = new ObjectAnimationUsingKeyFrames() { Duration = TimeSpan.FromSeconds(0) };
            Storyboard.SetTarget(backgroundAnimation, this.FindName("backgroundBorder") as DependencyObject);
            Storyboard.SetTargetProperty(backgroundAnimation, new PropertyPath(System.Windows.Controls.Border.BackgroundProperty));
            backgroundAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame(new SolidColorBrush(Colors.Transparent)));
            storyBoard.Children.Add(backgroundAnimation);

            storyBoard.Freeze();
            //sb.Begin(this.Template.FindName("TemplateRoot", this) as System.Windows.Controls.Grid);
            return storyBoard;
        }

        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.WidthChanged)
            {
                this.UpdateTemplateSettings();
            }
        }


        private void SetStoryBoard()
        {
            //System.Diagnostics.Debugger.Break();
            var root = this.Template.FindName("TemplateRoot", this) as FrameworkElement;
            var stateGroups = VisualStateManager.GetVisualStateGroups(root);
            var states = (stateGroups[0] as VisualStateGroup).States;
            foreach (var item in states)
            {
                if ((item as VisualState).Name == "Indeterminate")
                {
                    (item as VisualState).Storyboard = this.CreateStoryBoard();
                    VisualStateManager.GoToState(this, "Indeterminate", true);

                }
            }
        }

        private void UpdateContainerAnimationEndPositionTemplateSetting()
        {
            if (this.ActualWidth <= 181)
            {
                this.ContainerAnimationEndPositionTemplateSetting = (3.917 / 9 * this.ActualWidth) - (309.19 / 9);
            }
            else if (this.ActualWidth <= 381)
            {
                this.ContainerAnimationEndPositionTemplateSetting = (3.917 / 9 * this.ActualWidth) - (458.417 / 9);
            }
            else
            {
                this.ContainerAnimationEndPositionTemplateSetting = (3.917 / 9 * this.ActualWidth) - (570.917 / 9);
            }
        }

        private void UpdateContainerAnimationStartPositionTemplateSetting()
        {
            if (this.ActualWidth <= 181)
            {
                this.ContainerAnimationStartPositionTemplateSetting = -34;
            }
            else if (this.ActualWidth <= 381)
            {
                this.ContainerAnimationStartPositionTemplateSetting = -50.5;
            }
            else
            {
                this.ContainerAnimationStartPositionTemplateSetting = -63;
            }
        }

        private void UpdateEllipseAnimationEndPositionTemplateSetting()
        {
            this.EllipseAnimationEndPositionTemplateSetting = (this.ActualWidth - 1) * 2 / 3;
        }

        private void UpdateEllipseAnimationWellPositionTemplateSetting()
        {
            this.EllipseAnimationWellPositionTemplateSetting = (this.ActualWidth - 1) / 3;
        }

        private void UpdateEllipseDiameterTemplateSetting()
        {
            if (this.ActualWidth <= 181)
            {
                this.EllipseDiameterTemplateSetting = 4;
            }
            else if (this.ActualWidth <= 381)
            {
                this.EllipseDiameterTemplateSetting = 5;
            }
            else
            {
                this.EllipseDiameterTemplateSetting = 6;
            }
        }

        private void UpdateEllipseOffsetTemplateSetting()
        {
            if (this.ActualWidth <= 181)
            {
                this.EllipseOffsetTemplateSetting = 4;
            }
            else if (this.ActualWidth <= 381)
            {
                this.EllipseOffsetTemplateSetting = 7;
            }
            else
            {
                this.EllipseOffsetTemplateSetting = 9;
            }
        }

        private void UpdateTemplateSettings()
        {
            this.UpdateContainerAnimationEndPositionTemplateSetting();
            this.UpdateContainerAnimationStartPositionTemplateSetting();
            this.UpdateEllipseAnimationEndPositionTemplateSetting();
            this.UpdateEllipseAnimationWellPositionTemplateSetting();
            this.UpdateEllipseDiameterTemplateSetting();
            this.UpdateEllipseOffsetTemplateSetting();
            this.SetStoryBoard();
        }
    }
}